/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = rtcp_packet.c                                      */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/20 by songbb                               */
/*******************************************************************/

#include <json-c/json.h>

#include "frct_comm.h"

#include "rtcp_comm.h"
#include "rtcp_core.h"
#include "rtcp_packet.h"
#include "rtcp_header.h"

/*******************************************************************************
*  FUNC     :  解析 SR 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*           :  i_source_count                           (计数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc3550#section-6.4.1
*******************************************************************************/
FR_STATIC int __rtcp_dissect_sr(L7_rtcp_packet *p_st_rtcp_packet
                                , int i_source_count
                                , json_object *json_parent
                                , json_object *json_trans_title)
{
    uint32_t id = 0;
    /**
     * 它记录了SR报文的发送时刻，该值可被用来估测RTP报文或连续数据的平均发送速率。
     * 该时间戮为绝对时间戮，64位的前32位是从1900年1月1日0时开始到现在的以秒为单位的整数部分，后32位是此时间的小数部分。
     */
    uint32_t NTP_timestamp_MSW = 0; // NTP timestamp, most significant word
    uint32_t NTP_timestamp_LSW = 0; // NTP timestamp, least significant word

    uint32_t RTP_timestamp = 0; // RTP时间戮，同NTP时间戮相同，不过它的计时单位和计时原点与RTP数据报文的时间戳相同，该值可为码流内部或码流间的同步控制机制所选用。
    uint32_t sender_packet_count = 0; // 发送报文计数，它记录了到该SR报文发送时所发的RTP数据报文的总数。
    uint32_t sender_octet_count = 0; //  发送字节计数，它记录了到该SR报文发送时所发的连续数据的字节总数。
    int i_loop;
    uint32_t source_ssrc = 0;
    uint8_t fraction_lost = 0; // 丢失百分比，它表示自上一个SR或RR报文发送后，在数据接收过程中丢失的RTP报文数同所应收到的RTP报文总数的百分比。
    uint32_t packets_lost = 0; // 包丢失累计数，它记录了到该RTCP报文发送时，在接收过程中所丢失的RTP数据报文的总数。
    uint32_t ext_high_seq = 0; // 最大扩展次序号

    uint32_t jitter = 0; // 包间抖动，其所含内容是对数据传输过程中RTP报文所经历的延时抖动的一种估测，由下述两式确定。其中S为RTP报文的时间戳值，R为RTP报文的到达时刻。IJ值可以大致反映RTCP报文发送时网络的拥塞状况。
    uint32_t lsr = 0; // 上一个SR，其值为NTP时间戳的中间32位，表示最近收到SR报文的时间。
    uint32_t dlsr = 0; // 自从上一个SR的延时，单位为1/65536秒，其值为最近收到的SR报文到发送该RTCP报文的延时。

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &id, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &NTP_timestamp_MSW, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &NTP_timestamp_LSW, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &RTP_timestamp, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &sender_packet_count, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &sender_octet_count, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    json_object *json = json_object_new_object();
    json_object *json_source_array = NULL;
    json_object *json_source = NULL;
    json_object *json_src_title_array = NULL;
    json_object *json_src_title = NULL;
    json_object_object_add(json, "packet_type", json_object_new_string("SR"));
    json_object_object_add(json, "id", json_object_new_int64(id));
    json_object_object_add(json, "ntp_timestamp_msw", json_object_new_int64(NTP_timestamp_MSW));
    json_object_object_add(json, "ntp_timestamp_lsw", json_object_new_int64(NTP_timestamp_LSW));
    json_object_object_add(json, "rtp_timestamp", json_object_new_int64(RTP_timestamp));
    json_object_object_add(json, "sender_packet_count", json_object_new_int64(sender_packet_count));
    json_object_object_add(json, "sender_octet_count", json_object_new_int64(sender_octet_count));

    json_object_object_add(json_trans_title, "type", json_object_new_string("SR"));
    json_object_object_add(json_trans_title, "id", json_object_new_int64(id));
    json_object_object_add(json_trans_title, "packets", json_object_new_int64(sender_packet_count));
    json_object_object_add(json_trans_title, "octets", json_object_new_int64(sender_octet_count));

//    RTCP_PRINT_FATAL("id:[%u]\n", id);
//    RTCP_PRINT_FATAL("NTP_timestamp_MSW:[%u]\n", NTP_timestamp_MSW);
//    RTCP_PRINT_FATAL("NTP_timestamp_LSW:[%u]\n", NTP_timestamp_LSW);
//    RTCP_PRINT_FATAL("RTP_timestamp:[%u]\n", RTP_timestamp);
//    RTCP_PRINT_FATAL("sender_packet_count:[%u]\n", sender_packet_count);
//    RTCP_PRINT_FATAL("sender_octet_count:[%u]\n", sender_octet_count);

    if ((json_source_array = json_object_new_array()) == NULL || (json_src_title_array = json_object_new_array()) == NULL)
        goto error;

    for (i_loop = 0; i_loop < i_source_count; i_loop++)
    {
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &source_ssrc, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &fraction_lost) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 3, &packets_lost, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &ext_high_seq, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &jitter, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &lsr, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &dlsr, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;

        json_source = json_object_new_object();
        json_object_object_add(json_source, "id", json_object_new_int64(source_ssrc));
        json_object_object_add(json_source, "fraction_lost", json_object_new_int(fraction_lost));
        json_object_object_add(json_source, "packets_lost", json_object_new_int64(packets_lost));
        json_object_object_add(json_source, "ext_high_seq", json_object_new_int(ext_high_seq));
        json_object_object_add(json_source, "jitter", json_object_new_int64(jitter));
        json_object_object_add(json_source, "lsr", json_object_new_int64(lsr));
        json_object_object_add(json_source, "dlsr", json_object_new_int64(dlsr));
        json_object_array_add(json_source_array, json_source);

        json_src_title = json_object_new_object();
        json_object_object_add(json_src_title, "id", json_object_new_int64(source_ssrc));
        json_object_object_add(json_src_title, "fraction_lost", json_object_new_int(fraction_lost));
        json_object_object_add(json_src_title, "packets_lost", json_object_new_int64(packets_lost));
        json_object_array_add(json_src_title_array, json_src_title);

//        RTCP_PRINT_FATAL("source_ssrc:[%u]\n", source_ssrc);
//        RTCP_PRINT_FATAL("fraction_lost:[%u]\n", fraction_lost);
//        RTCP_PRINT_FATAL("packets_lost:[%u]\n", packets_lost);
//        RTCP_PRINT_FATAL("ext_high_seq:[%u]\n", ext_high_seq);
//        RTCP_PRINT_FATAL("jitter:[%u]\n", jitter);
//        RTCP_PRINT_FATAL("lsr:[%u]\n", lsr);
//        RTCP_PRINT_FATAL("dlsr:[%u]\n", dlsr);
    }
    json_object_object_add(json, "report_blocks", json_source_array);
    json_object_object_add(json_trans_title, "report_blocks", json_src_title_array);
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    json_object_put(json);
    json_object_put(json_source_array);
    json_object_put(json_source);
    json_object_put(json_src_title_array);
    json_object_put(json_src_title);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 RR 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*           :  i_source_count                           (计数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc3550#section-6.4.2
*******************************************************************************/
FR_STATIC int __rtcp_dissect_rr(L7_rtcp_packet *p_st_rtcp_packet
                                , int i_source_count
                                , json_object *json_parent
                                , json_object *json_trans_title)
{
    uint32_t id = 0;
    int i_loop;
    uint32_t source_ssrc = 0;
    uint8_t fraction_lost = 0; // 丢失百分比，它表示自上一个SR或RR报文发送后，在数据接收过程中丢失的RTP报文数同所应收到的RTP报文总数的百分比。
    uint32_t packets_lost = 0; // 包丢失累计数，它记录了到该RTCP报文发送时，在接收过程中所丢失的RTP数据报文的总数。
    uint32_t ext_high_seq = 0; // 最大扩展次序号

    uint32_t jitter = 0; // 包间抖动，其所含内容是对数据传输过程中RTP报文所经历的延时抖动的一种估测，由下述两式确定。其中S为RTP报文的时间戳值，R为RTP报文的到达时刻。IJ值可以大致反映RTCP报文发送时网络的拥塞状况。
    uint32_t lsr = 0; // 上一个SR，其值为NTP时间戳的中间32位，表示最近收到SR报文的时间。
    uint32_t dlsr = 0; // 自从上一个SR的延时，单位为1/65536秒，其值为最近收到的SR报文到发送该RTCP报文的延时。

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &id, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    json_object *json = json_object_new_object();
    json_object *json_source_array = NULL;
    json_object *json_source = NULL;
    json_object *json_src_title_array = NULL;
    json_object *json_src_title = NULL;
    json_object_object_add(json, "packet_type", json_object_new_string("RR"));
    json_object_object_add(json, "id", json_object_new_int64(id));

    json_object_object_add(json_trans_title, "type", json_object_new_string("RR"));
    json_object_object_add(json_trans_title, "id", json_object_new_int64(id));

//    RTCP_PRINT_FATAL("id:[%u]\n", id);

    if ((json_source_array = json_object_new_array()) == NULL || (json_src_title_array = json_object_new_array()) == NULL)
        goto error;

    for (i_loop = 0; i_loop < i_source_count; i_loop++)
    {
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &source_ssrc, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &fraction_lost) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 3, &packets_lost, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &ext_high_seq, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &jitter, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &lsr, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &dlsr, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;

        json_source = json_object_new_object();
        json_object_object_add(json_source, "id", json_object_new_int64(source_ssrc));
        json_object_object_add(json_source, "fraction_lost", json_object_new_int(fraction_lost));
        json_object_object_add(json_source, "packets_lost", json_object_new_int64(packets_lost));
        json_object_object_add(json_source, "ext_high_seq", json_object_new_int(ext_high_seq));
        json_object_object_add(json_source, "jitter", json_object_new_int64(jitter));
        json_object_object_add(json_source, "lsr", json_object_new_int64(lsr));
        json_object_object_add(json_source, "dlsr", json_object_new_int64(dlsr));
        json_object_array_add(json_source_array, json_source);

        json_src_title = json_object_new_object();
        json_object_object_add(json_src_title, "id", json_object_new_int64(source_ssrc));
        json_object_object_add(json_src_title, "fraction_lost", json_object_new_int(fraction_lost));
        json_object_object_add(json_src_title, "packets_lost", json_object_new_int64(packets_lost));
        json_object_array_add(json_src_title_array, json_src_title);

//        RTCP_PRINT_FATAL("source_ssrc:[%u]\n", source_ssrc);
//        RTCP_PRINT_FATAL("fraction_lost:[%u]\n", fraction_lost);
//        RTCP_PRINT_FATAL("packets_lost:[%u]\n", packets_lost);
//        RTCP_PRINT_FATAL("ext_high_seq:[%u]\n", ext_high_seq);
//        RTCP_PRINT_FATAL("jitter:[%u]\n", jitter);
//        RTCP_PRINT_FATAL("lsr:[%u]\n", lsr);
//        RTCP_PRINT_FATAL("dlsr:[%u]\n", dlsr);
    }
    json_object_object_add(json, "report_blocks", json_source_array);
    json_object_object_add(json_trans_title, "report_blocks", json_src_title_array);
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    json_object_put(json);
    json_object_put(json_source_array);
    json_object_put(json_source);
    json_object_put(json_src_title_array);
    json_object_put(json_src_title);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 SDES 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*           :  i_source_count                           (计数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc3550#section-6.5
*******************************************************************************/
FR_STATIC int __rtcp_dissect_sdes(L7_rtcp_packet *p_st_rtcp_packet
                                , int i_source_count
                                , json_object *json_parent)
{
    int i_loop;
    uint32_t identifier = 0;
    uint8_t sdes_type = 0;
    uint8_t item_len = 0;
    uint8_t prefix_len = 0;
    char *p_prefix_string = NULL;
    char *p_text = NULL;

    json_object *json = json_object_new_object();
    json_object *json_chunk_array = NULL;
    json_object *json_chunk = NULL;
    json_object *json_items_array = NULL;
    json_object *json_item = NULL;
    json_object_object_add(json, "packet_type", json_object_new_string("SDES"));
    if (i_source_count > 0 && (json_chunk_array = json_object_new_array()) == NULL)
        goto error;

    for (i_loop = 0; i_loop < i_source_count; i_loop++)
    {
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &identifier, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
//        RTCP_PRINT_FATAL("identifier:[%u]\n", identifier);

        json_chunk = json_object_new_object();
        json_object_object_add(json_chunk, "id", json_object_new_int64(identifier));

        json_items_array = json_object_new_array();
        while (bytebuff_remaining(p_st_rtcp_packet->p_st_packet) > 0)
        {
            if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &sdes_type) != FR_SUCC)
                goto error;
            if (sdes_type == RTCP_SDES_END)
                break;
            if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &item_len) != FR_SUCC)
                goto error;
            if (item_len != 0)
            {
                json_item = json_object_new_object();
                switch (sdes_type)
                {
                    case RTCP_SDES_CNAME:
                        json_object_object_add(json_item, "type", json_object_new_string("CNAME"));
                        break;
                    case RTCP_SDES_NAME:
                        json_object_object_add(json_item, "type", json_object_new_string("NAME"));
                        break;
                    case RTCP_SDES_EMAIL:
                        json_object_object_add(json_item, "type", json_object_new_string("EMAIL"));
                        break;
                    case RTCP_SDES_PHONE:
                        json_object_object_add(json_item, "type", json_object_new_string("PHONE"));
                        break;
                    case RTCP_SDES_LOC:
                        json_object_object_add(json_item, "type", json_object_new_string("LOC"));
                        break;
                    case RTCP_SDES_TOOL:
                        json_object_object_add(json_item, "type", json_object_new_string("TOOL"));
                        break;
                    case RTCP_SDES_NOTE:
                        json_object_object_add(json_item, "type", json_object_new_string("NOTE"));
                        break;
                    case RTCP_SDES_PRIV:
                        json_object_object_add(json_item, "type", json_object_new_string("PRIV"));
                        break;
                    case RTCP_SDES_H323_CADDR:
                        json_object_object_add(json_item, "type", json_object_new_string("H323_CADDR"));
                        break;
                    case RTCP_SDES_APSI:
                        json_object_object_add(json_item, "type", json_object_new_string("APSI"));
                        break;
                    default:
                        json_object_object_add(json_item, "type", json_object_new_string("UNKNOWN"));
                }

                if (sdes_type == RTCP_SDES_PRIV)
                {
                    if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &prefix_len) != FR_SUCC)
                        goto error;
                    if (prefix_len + 1 > item_len)
                    {
                        if (bytebuff_skip(p_st_rtcp_packet->p_st_packet, prefix_len) != FR_SUCC)
                            goto error;
                        json_object_put(json_item);
                        continue;
                    }
                    if ((p_prefix_string = (char *) frmalloc((prefix_len + 1) * sizeof(char))) == NULL)
                    {
                        RTCP_MALLOCK_ERR;
                        goto error;
                    }
                    if (bytebuff_get_bytes(p_st_rtcp_packet->p_st_packet, p_prefix_string, prefix_len) != FR_SUCC)
                        goto error;
                    p_prefix_string[prefix_len] = '\0';
//                    RTCP_PRINT_FATAL("p_prefix_string:[%s]\n", p_prefix_string);
                    json_object_object_add(json_item, "prefix_string", json_object_new_string(p_prefix_string));
                    rtcp_free((void **) &p_prefix_string);
                    item_len -= prefix_len + 1;
                    if (item_len == 0)
                    {
                        json_object_put(json_item);
                        continue;
                    }
                }

                if ((p_text = (char *) frmalloc((item_len + 1) * sizeof(char))) == NULL)
                {
                    RTCP_MALLOCK_ERR;
                    goto error;
                }
                if (bytebuff_get_bytes(p_st_rtcp_packet->p_st_packet, p_text, item_len) != FR_SUCC)
                    goto error;
                p_text[item_len] = '\0';
//                RTCP_PRINT_FATAL("p_text:[%s]\n", p_text);
                json_object_object_add(json_item, "text", json_object_new_string(p_text));
                rtcp_free((void **) &p_text);

                json_object_array_add(json_items_array, json_item);
            }
        }
        json_object_object_add(json_chunk, "items", json_items_array);
        json_object_array_add(json_chunk_array, json_chunk);
    }
    json_object_object_add(json, "chunks", json_chunk_array);
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    rtcp_free((void **) &p_prefix_string);
    rtcp_free((void **) &p_text);
    json_object_put(json);
    json_object_put(json_chunk_array);
    json_object_put(json_chunk);
    json_object_put(json_items_array);
    json_object_put(json_item);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 BYE 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*           :  i_source_count                           (计数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc3550#section-6.6
*******************************************************************************/
FR_STATIC int __rtcp_dissect_bye(L7_rtcp_packet *p_st_rtcp_packet
                                , int i_source_count
                                , json_object *json_parent)
{
    int i_loop;
    uint32_t identifier = 0;
    uint8_t reason_len = 0;
    char *p_reason = NULL;
    json_object *json = json_object_new_object();
    json_object *json_id_array = NULL;
    json_object_object_add(json, "packet_type", json_object_new_string("BYE"));

    if (i_source_count > 0 && (json_id_array = json_object_new_array()) == NULL)
        goto error;
    for (i_loop = 0; i_loop < i_source_count; i_loop++)
    {
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &identifier, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
//        RTCP_PRINT_FATAL("identifier:[%u]\n", identifier);
        json_object_array_add(json_id_array, json_object_new_int64(identifier));
    }
    if (i_source_count > 0)
        json_object_object_add(json, "id", json_id_array);

    // TODO: 修改if条件
    if (bytebuff_remaining(p_st_rtcp_packet->p_st_packet) > 0)
    {
        if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &reason_len) != FR_SUCC)
            goto error;

        if ((p_reason = (char *) frmalloc((reason_len + 1) * sizeof(char))) == NULL)
        {
            RTCP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes(p_st_rtcp_packet->p_st_packet, p_reason, reason_len) != FR_SUCC)
            goto error;
        p_reason[reason_len] = '\0';
//        RTCP_PRINT_FATAL("reason for leaving:[%s]\n", p_reason);
        json_object_object_add(json, "reason", json_object_new_string(p_reason));
        rtcp_free((void **) &p_reason);
    }
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    rtcp_free((void **) &p_reason);
    json_object_put(json);
    json_object_put(json_id_array);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 APP 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc3550#section-6.7
*******************************************************************************/
FR_STATIC int __rtcp_dissect_app(L7_rtcp_packet *p_st_rtcp_packet
                                , json_object *json_parent)
{
    uint32_t sender_ssrc = 0;
    uint32_t identifier = 0;
    unsigned int ui_appname_len = 4;
    char *p_appname = NULL;
    json_object *json = json_object_new_object();
    json_object_object_add(json, "packet_type", json_object_new_string("APP"));

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &sender_ssrc, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
//    RTCP_PRINT_FATAL("sender_ssrc:[%u]\n", sender_ssrc);
    json_object_object_add(json, "id", json_object_new_int64(sender_ssrc));

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &identifier, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    if ((p_appname = (char *) frmalloc((ui_appname_len + 1) * sizeof(char))) == NULL)
    {
        RTCP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes(p_st_rtcp_packet->p_st_packet, p_appname, ui_appname_len) != FR_SUCC)
        goto error;
    p_appname[ui_appname_len] = '\0';
//    RTCP_PRINT_FATAL("p_appname:[%s]\n", p_appname);
    json_object_object_add(json, "app", json_object_new_string(p_appname));
    rtcp_free((void **) &p_appname);
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    rtcp_free((void **) &p_appname);
    json_object_put(json);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 FIR 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc2032#section-5.2.1
*******************************************************************************/
FR_STATIC int __rtcp_dissect_fir(L7_rtcp_packet *p_st_rtcp_packet
                                , json_object *json_parent)
{
    uint32_t sender_ssrc = 0;
    json_object *json = json_object_new_object();
    json_object_object_add(json, "packet_type", json_object_new_string("FIR"));

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &sender_ssrc, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
//    RTCP_PRINT_FATAL("sender_ssrc:[%u]\n", sender_ssrc);
    json_object_object_add(json, "id", json_object_new_int64(sender_ssrc));
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    json_object_put(json);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 NACK 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc2032#section-5.2.2
*******************************************************************************/
FR_STATIC int __rtcp_dissect_nack(L7_rtcp_packet *p_st_rtcp_packet
                                , json_object *json_parent)
{
    uint32_t sender_ssrc = 0;
    uint16_t fsn = 0;
    uint16_t blp = 0;
    json_object *json = json_object_new_object();
    json_object_object_add(json, "packet_type", json_object_new_string("NACK"));

    if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &sender_ssrc, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
//    RTCP_PRINT_FATAL("sender_ssrc:[%u]\n", sender_ssrc);
    json_object_object_add(json, "id", json_object_new_int64(sender_ssrc));

    if (bytebuff_get_short(p_st_rtcp_packet->p_st_packet, 2, &fsn, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
//    RTCP_PRINT_FATAL("fsn:[%u]\n", fsn);
    json_object_object_add(json, "fsn", json_object_new_int(fsn));

    if (bytebuff_get_short(p_st_rtcp_packet->p_st_packet, 2, &blp, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;
//    RTCP_PRINT_FATAL("blp:[%u]\n", blp);
    json_object_object_add(json, "blp", json_object_new_int(blp));
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    json_object_put(json);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析 IJ 类型包
*  ARGS     :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_rtcp_report                        (数据出力)
*           :  i_source_count                           (计数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*  REFERENCE: https://tools.ietf.org/html/rfc5450#section-4
*******************************************************************************/
FR_STATIC int __rtcp_dissect_ij(L7_rtcp_packet *p_st_rtcp_packet
                                , int i_source_count
                                , json_object *json_parent)
{
    int i_loop;
    uint32_t jitter = 0;
    json_object *json = json_object_new_object();
    json_object *json_jitter_array = NULL;
    json_object_object_add(json, "packet_type", json_object_new_string("IJ"));

    if (i_source_count > 0 && (json_jitter_array = json_object_new_array()) == NULL)
        goto error;
    for (i_loop = 0; i_loop < i_source_count; i_loop++)
    {
        if (bytebuff_get_int(p_st_rtcp_packet->p_st_packet, 4, &jitter, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
//        RTCP_PRINT_FATAL("jitter:[%u]\n", jitter);
        json_object_array_add(json_jitter_array, json_object_new_int64(jitter));
    }
    if (i_source_count > 0)
        json_object_object_add(json, "id", json_jitter_array);
    json_object_array_add(json_parent, json);

    return FR_SUCC;
error:
    json_object_put(json);
    json_object_put(json_jitter_array);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析RTCP请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (RTCP私有的session)
*           :  *p_st_rtcp_packet                        (RTCP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int rtcp_analyze_packet(Conntrack *p_st_conn
                        , L7session_rtcp *p_st_sess
                        , L7_rtcp_packet *p_st_rtcp_packet
                        , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;
    json_object *json = json_object_new_array();
    json_object *json_trans_title = json_object_new_object();

    while (bytebuff_remaining(p_st_rtcp_packet->p_st_packet) > 0)
    {
        int i_pos_begin;
        uint8_t firstbyte;
        int i_count;
        uint8_t tmp;
        Rtcp_PT rtcp_pt;
        uint16_t length;

        if ((i_pos_begin = bytebuff_getPosition(p_st_rtcp_packet->p_st_packet)) < 0)
            goto error;

        if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &firstbyte) != FR_SUCC)
            goto error;
        i_count = APM_RTCP_COUNT(firstbyte);

        // Packet type
        if (bytebuff_get_char(p_st_rtcp_packet->p_st_packet, &tmp) != FR_SUCC)
            goto error;
        rtcp_pt = (Rtcp_PT) tmp;

        // Packet length
        if (bytebuff_get_short(p_st_rtcp_packet->p_st_packet, 2, &length, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        length = (uint16_t) ((length + 1) * 4);

//        RTCP_PRINT_FATAL("i_count:[%u]\n", i_count);
//        RTCP_PRINT_FATAL("length:[%u]\n", length);

        switch (rtcp_pt)
        {
            case RTCP_PT_SR:
                RTCP_PRINT_INFO("dissect SR\n");
                if (__rtcp_dissect_sr(p_st_rtcp_packet, i_count, json, json_trans_title) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_RR:
                RTCP_PRINT_INFO("dissect RR\n");
                if (__rtcp_dissect_rr(p_st_rtcp_packet, i_count, json, json_trans_title) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_SDES:
                RTCP_PRINT_INFO("dissect SDES\n");
                if (__rtcp_dissect_sdes(p_st_rtcp_packet, i_count, json) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_BYE:
                RTCP_PRINT_INFO("dissect BYE\n");
                if (__rtcp_dissect_bye(p_st_rtcp_packet, i_count, json) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_APP:
                RTCP_PRINT_INFO("dissect APP\n");
                if (__rtcp_dissect_app(p_st_rtcp_packet, json) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_FIR:
                RTCP_PRINT_INFO("dissect FIR\n");
                if (__rtcp_dissect_fir(p_st_rtcp_packet, json) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_NACK:
                RTCP_PRINT_INFO("dissect NACK\n");
                if (__rtcp_dissect_nack(p_st_rtcp_packet, json) != FR_SUCC)
                    goto error;
                break;
            case RTCP_PT_IJ:
                RTCP_PRINT_INFO("dissect IJ\n");
                if (__rtcp_dissect_ij(p_st_rtcp_packet, i_count, json) != FR_SUCC)
                    goto error;
                break;
            default:
                goto error;
        }

        if (bytebuff_setPosition(p_st_rtcp_packet->p_st_packet, i_pos_begin + length) != FR_SUCC)
            goto error;
    }

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, FR_NO) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, &(p_st_rtcp_packet->st_timestamp_first)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, &(p_st_rtcp_packet->st_timestamp_first)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, 0) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, (unsigned long) bytebuff_length(p_st_rtcp_packet->p_st_packet)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_RTCP_REPORT_KEY, json_object_to_json_string(json)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, json_object_to_json_string(json_trans_title)) != FR_SUCC)
        goto error;

    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;

    RTCP_PRINT(KLIMEGREEN""APM_REPORT_KEY_TRANS_TITLE":\n %s\n"RESET, json_object_to_json_string_ext(json_trans_title, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
    RTCP_PRINT(KORANGE""APM_RTCP_REPORT_KEY":\n %s\n"RESET, json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));

    json_object_put(json);
    json_object_put(json_trans_title);

    return FR_SUCC;
error:
    json_object_put(json);
    json_object_put(json_trans_title);
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    return FR_FAIL;
}
